﻿using System;
using Microsoft.Linq.Expressions;
using System.Text;

namespace Cjc.Calculation.ExpressionEngine
{
	public class ExpressionTreeDump : BlindExpressionTreeVisitor
	{
		private int indentSize;
		private int indent = 0;
		private StringBuilder sb = new StringBuilder();

		public static string Dump( Expression node )
		{
			var dump = new ExpressionTreeDump();
			dump.Visit( node );
			return dump.Text;
		}

		public ExpressionTreeDump()
			: this( 2 )
		{
		}

		public ExpressionTreeDump( int indentSize )
		{
			this.indentSize = indentSize;
		}

		public string Text
		{
			get { return sb.ToString(); }
		}

		protected override TResult Visit<T, TResult>( T node, Func<T, TResult> p )
		{
			var e = node as Expression;

			var text = ( e != null )
				? string.Format( "{{{0}}} {1}", e.NodeType, e )
				: node.ToString();

			sb.AppendLine( new string( ' ', indent ) + text );

			indent += indentSize;

			var result = base.Visit<T, TResult>( node, p );

			indent -= indentSize;

			return result;
		}

	}

	public class BlindExpressionTreeVisitor : ExpressionVisitor
	{
		protected virtual TResult Visit<T, TResult>( T node, Func<T, TResult> p )
		{
			return p( node );
		}

		#region Overrides

		protected override Expression VisitAssignment( AssignmentExpression node ) { return Visit( node, e => BaseAssignment( e ) );}
		protected override Expression VisitBinary( BinaryExpression node ) { return Visit( node, e => BaseBinary( e ) ); }
		protected override Expression VisitBlock( Block node ) { return Visit( node, e => BaseBlock( e ) ); }
		protected override CatchBlock VisitCatchBlock( CatchBlock node ) { return Visit( node, e => BaseCatchBlock( e ) ); }
		protected override Expression VisitConditional( ConditionalExpression node ) { return Visit( node, e => BaseConditional( e ) ); }
		protected override Expression VisitConstant( ConstantExpression node ) { return Visit( node, e => BaseConstant( e ) ); }
		protected override Expression VisitDoWhile( DoStatement node ) { return Visit( node, e => BaseDoWhile( e ) ); }
		protected override Expression VisitDynamic( DynamicExpression node ) { return Visit( node, e => BaseDynamic( e ) ); }
		protected override ElementInit VisitElementInit( ElementInit initializer ) { return Visit( initializer, e => BaseElementInit( e ) ); }
		protected override Expression VisitEmpty( EmptyStatement node ) { return Visit( node, e => BaseEmpty( e ) ); }
		protected override Expression VisitExtension( Expression node ) { return Visit( node, e => BaseExtension( e ) ); }
		protected override Expression VisitGoto( GotoExpression node ) { return Visit( node, e => BaseGoto( e ) ); }
		protected override Expression VisitIndex( IndexExpression node ) { return Visit( node, e => BaseIndex( e ) ); }
		protected override Expression VisitInvocation( InvocationExpression node ) { return Visit( node, e => BaseInvocation( e ) ); }
		protected override Expression VisitLabel( LabelExpression node ) { return Visit( node, e => BaseLabel( e ) ); }
		protected override LabelTarget VisitLabelTarget( LabelTarget node ) { return Visit( node, e => BaseLabelTarget( e ) ); }
		protected override Expression VisitLambda( LambdaExpression node ) { return Visit( node, e => BaseLambda( e ) ); }
		protected override Expression VisitListInit( ListInitExpression node ) { return Visit( node, e => BaseListInit( e ) ); }
		protected override Expression VisitLoop( LoopStatement node ) { return Visit( node, e => BaseLoop( e ) ); }
		protected override Expression VisitMemberAccess( MemberExpression node ) { return Visit( node, e => BaseMemberAccess( e ) ); }
		protected override MemberAssignment VisitMemberAssignment( MemberAssignment assignment ) { return Visit( assignment, e => BaseMemberAssignment( e ) ); }
		protected override MemberBinding VisitMemberBinding( MemberBinding binding ) { return Visit( binding, e => BaseMemberBinding( e ) ); }
		protected override Expression VisitMemberInit( MemberInitExpression node ) { return Visit( node, e => BaseMemberInit( e ) ); }
		protected override MemberListBinding VisitMemberListBinding( MemberListBinding binding ) { return Visit( binding, e => BaseMemberListBinding( e ) ); }
		protected override MemberMemberBinding VisitMemberMemberBinding( MemberMemberBinding binding ) { return Visit( binding, e => BaseMemberMemberBinding( e ) ); }
		protected override Expression VisitMethodCall( MethodCallExpression node ) { return Visit( node, e => BaseMethodCall( e ) ); }
		protected override Expression VisitNew( NewExpression node ) { return Visit( node, e => BaseNew( e ) ); }
		protected override Expression VisitNewArray( NewArrayExpression node ) { return Visit( node, e => BaseNewArray( e ) ); }
		protected override Expression VisitParameter( ParameterExpression node ) { return Visit( node, e => BaseParameter( e ) ); }
		protected override Expression VisitReturn( ReturnStatement node ) { return Visit( node, e => BaseReturn( e ) ); }
		protected override Expression VisitRuntimeVariables( LocalScopeExpression node ) { return Visit( node, e => BaseRuntimeVariables( e ) ); }
		protected override Expression VisitScope( ScopeExpression node ) { return Visit( node, e => BaseScope( e ) ); }
		protected override Expression VisitSwitch( SwitchStatement node ) { return Visit( node, e => BaseSwitch( e ) ); }
		protected override SwitchCase VisitSwitchCase( SwitchCase node ) { return Visit( node, e => BaseSwitchCase( e ) ); }
		protected override Expression VisitThrow( ThrowStatement node ) { return Visit( node, e => BaseThrow( e ) ); }
		protected override Expression VisitTry( TryStatement node ) { return Visit( node, e => BaseTry( e ) ); }
		protected override Expression VisitTypeBinary( TypeBinaryExpression node ) { return Visit( node, e => BaseTypeBinary( e ) ); }
		protected override Expression VisitUnary( UnaryExpression node ) { return Visit( node, e => BaseUnary( e ) ); }

		#endregion

		#region Base invokers

		private Expression BaseAssignment( AssignmentExpression node ) { return base.VisitAssignment( node ); }
		protected Expression BaseBinary( BinaryExpression node ) { return base.VisitBinary( node ); }
		protected Expression BaseBlock( Block node ) { return base.VisitBlock( node ); }
		protected CatchBlock BaseCatchBlock( CatchBlock node ) { return base.VisitCatchBlock( node ); }
		protected Expression BaseConditional( ConditionalExpression node ) { return base.VisitConditional( node ); }
		protected Expression BaseConstant( ConstantExpression node ) { return base.VisitConstant( node ); }
		protected Expression BaseDoWhile( DoStatement node ) { return base.VisitDoWhile( node ); }
		protected Expression BaseDynamic( DynamicExpression node ) { return base.VisitDynamic( node ); }
		protected ElementInit BaseElementInit( ElementInit initializer ) { return base.VisitElementInit( initializer ); }
		protected Expression BaseEmpty( EmptyStatement node ) { return base.VisitEmpty( node ); }
		protected Expression BaseExtension( Expression node ) { return base.VisitExtension( node ); }
		protected Expression BaseGoto( GotoExpression node ) { return base.VisitGoto( node ); }
		protected Expression BaseIndex( IndexExpression node ) { return base.VisitIndex( node ); }
		protected Expression BaseInvocation( InvocationExpression node ) { return base.VisitInvocation( node ); }
		protected Expression BaseLabel( LabelExpression node ) { return base.VisitLabel( node ); }
		protected LabelTarget BaseLabelTarget( LabelTarget node ) { return base.VisitLabelTarget( node ); }
		protected Expression BaseLambda( LambdaExpression node ) { return base.VisitLambda( node ); }
		protected Expression BaseListInit( ListInitExpression node ) { return base.VisitListInit( node ); }
		protected Expression BaseLoop( LoopStatement node ) { return base.VisitLoop( node ); }
		protected Expression BaseMemberAccess( MemberExpression node ) { return base.VisitMemberAccess( node ); }
		protected MemberAssignment BaseMemberAssignment( MemberAssignment assignment ) { return base.VisitMemberAssignment( assignment ); }
		protected MemberBinding BaseMemberBinding( MemberBinding binding ) { return base.VisitMemberBinding( binding ); }
		protected Expression BaseMemberInit( MemberInitExpression node ) { return base.VisitMemberInit( node ); }
		protected MemberListBinding BaseMemberListBinding( MemberListBinding binding ) { return base.VisitMemberListBinding( binding ); }
		protected MemberMemberBinding BaseMemberMemberBinding( MemberMemberBinding binding ) { return base.VisitMemberMemberBinding( binding ); }
		protected Expression BaseMethodCall( MethodCallExpression node ) { return base.VisitMethodCall( node ); }
		protected Expression BaseNew( NewExpression node ) { return base.VisitNew( node ); }
		protected Expression BaseNewArray( NewArrayExpression node ) { return base.VisitNewArray( node ); }
		protected Expression BaseParameter( ParameterExpression node ) { return base.VisitParameter( node ); }
		protected Expression BaseReturn( ReturnStatement node ) { return base.VisitReturn( node ); }
		protected Expression BaseRuntimeVariables( LocalScopeExpression node ) { return base.VisitRuntimeVariables( node ); }
		protected Expression BaseScope( ScopeExpression node ) { return base.VisitScope( node ); }
		protected Expression BaseSwitch( SwitchStatement node ) { return base.VisitSwitch( node ); }
		protected SwitchCase BaseSwitchCase( SwitchCase node ) { return base.VisitSwitchCase( node ); }
		protected Expression BaseThrow( ThrowStatement node ) { return base.VisitThrow( node ); }
		protected Expression BaseTry( TryStatement node ) { return base.VisitTry( node ); }
		protected Expression BaseTypeBinary( TypeBinaryExpression node ) { return base.VisitTypeBinary( node ); }
		protected Expression BaseUnary( UnaryExpression node ) { return base.VisitUnary( node ); }

		#endregion
	}
}